#include "widget.h"
#include <QApplication>

#include <PortSIPLib/PortSIPLib.hxx>
#include <PortSIPLib/PortSIPErrors.hxx>
#include <PortSIPLib/ICallbackParameters.hxx>
#include <PortSIPLib/AbstractCallbackDispatcher.hxx>

#define SIPPORT_MIN	5000


using namespace PortSIP;

void *m_SIPLib;
bool sipInitialized;
bool sipRegistered;
bool m_PCMU;
bool m_PCMA;
bool m_G729;
bool m_ILBC;
bool m_GSM;
bool m_G722;
bool m_SPEEX;
bool m_SPEEX_WB;
bool m_H263;
bool m_H2631998;
bool m_H264;
bool m_AEC;
bool m_VAD;
bool m_AGC;
bool m_CNG;
bool m_ANS;
bool m_AMRWB;
bool m_G7221;
bool m_AMR;
bool m_VP8;
bool m_PRACK;
bool m_Opus;
bool m_DND;

void initPortSIP();
void loadDevices();
void setSRTPType();
void updateAudioCodecs();
void updateVideoCodecs();
void initSettings();
void setVideoResolution();
void setVideoBitrate();
void onMessage(void *parameters);

class A : public AbstractCallbackDispatcher
{
    void onMessage(void *parameters)
    {
        if (parameters == NULL) return;

        char* c = (char*)parameters;
        ICallbackParameters* parameter = reinterpret_cast<ICallbackParameters *>(parameters);

        parameter->getEventType();

        FILE* file = fopen("data.txt", "a+");
        for (int i=0; i<1024*4; i++)
        {
            fprintf(file, "%4d", c[i]);
        }
        fputs("\n", file);
        fflush(file);
        fclose(file);

/*        if (parameters == NULL)
        {
            qDebug() << "NULL";
            return;
        }

        ICallbackParameters* parameter = reinterpret_cast<ICallbackParameters *>(parameters);

        char* c = (char*)parameters;

//        int eventType = ((int*)(&c[24]))[0];

   */
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
//    Widget w;
//    w.show();
    initPortSIP();
    return a.exec();
}

void initPortSIP()
{
    m_DND = false;
    m_PCMU= false;
    m_PCMA= false;
    m_G729= false;
    m_ILBC= false;
    m_GSM= false;
    m_G722= false;
    m_SPEEX= false;
    m_SPEEX_WB= false;
    m_H263= false;
    m_H2631998= false;
    m_H264= false;
    m_AEC= false;
    m_VAD = false;
    m_AGC = false;
    m_CNG = false;
    m_ANS = false;
    m_AMRWB = false;
    m_G7221 = false;
    m_AMR = false;
    m_VP8 = false;
    m_PRACK = false;
    m_Opus = false;

    int errorCode = 0;
    TRANSPORT_TYPE transport = TRANSPORT_UDP;
    PORTSIP_LOG_LEVEL level = PORTSIP_LOG_NONE;

    qDebug() << "Initializing...";
    A* a = new A();
    m_SIPLib = PortSIP_initialize(a, transport, level, NULL, 8, "PortSIP VoIP SDK 11.2", false, false, &errorCode);

    if(errorCode != 0)
    {
        qDebug() << "PortSIP_initialize failure.";
        return;
    }

    sipInitialized = true;
    qDebug() << "Initialized the SDK.";

    int localSIPPort = SIPPORT_MIN+rand()%5000;

    char localIp[32] = { 0 };

    int nics = PortSIP_getNICNums(m_SIPLib);

    for (int i = 0; i < nics; ++i)
    {
        PortSIP_getLocalIpAddress(m_SIPLib, i, localIp, 32);
        if (!strstr(localIp, ":"))
        {
            break;
        }
    }

    if (strlen(localIp) == 0)
    {
        PortSIP_unInitialize(m_SIPLib);
        m_SIPLib = NULL;
        sipInitialized = false;
        qDebug() << "Failed to get the local IP.";
        return;
    }

    const char* userDomain = NULL;
    const char* stunServer = NULL;
    int stunServerPort = 0;
    const char* outboundServer = NULL;
    int outboundServerPort = 0;

    errorCode = PortSIP_setUser(m_SIPLib,
                                "1002",
                                "display name",
                                "",
                                "a11223344",
                                "0.0.0.0",
                                // Use 0.0.0.0 for local IP then the SDK will choose an available local IP automatically.
                                // You also can specify a certain local IP to instead of "0.0.0.0", more details please read the SDK User Manual
                                localSIPPort,
                                userDomain,
                                "172.16.1.152",
                                5060,
                                stunServer,
                                stunServerPort,
                                outboundServer,
                                outboundServerPort);

    if(errorCode != 0)
    {
        PortSIP_unInitialize(m_SIPLib);
        //		m_LogList.ResetContent();
        m_SIPLib = NULL;
        sipInitialized = false;

        qDebug() << "PortSIP_setUser failure.";
        return;
    }

    qDebug() << "Registering...";
    errorCode = PortSIP_registerServer(m_SIPLib, 120, 3);
    qDebug() << "Registered";

    loadDevices();

    setSRTPType();

    int rt = PortSIP_setLicenseKey(m_SIPLib, "PORTSIP_TEST_LICENSE");
    if (rt == ECoreTrialVersionLicenseKey)
    {
        //QMessageBox::information(this, "Information", "This sample was built base on evaluation PortSIP VoIP SDK, which allows only three minutes conversation. The conversation will be cut off automatically after three minutes, then you can't hearing anything. Feel free contact us at: sales@portsip.com to purchase the official version.");
    }
    else if (rt == ECoreWrongLicenseKey)
    {
        qDebug() << "The wrong license key was detected, please check with sales@portsip.com or support@portsip.com";
    }

    //    PortSIP_setLocalVideoWindow(m_SIPLib, m_LocalVideo.m_hWnd);

    updateAudioCodecs();
    updateVideoCodecs();

    initSettings();

    setVideoResolution();
    setVideoBitrate();

    bool m_NeedRegister = true;
    if (m_NeedRegister)
    {
        errorCode = PortSIP_registerServer(m_SIPLib, 120, 3);
        if (errorCode != 0)
        {
            PortSIP_unInitialize(m_SIPLib);

            m_SIPLib = NULL;
            sipInitialized = false;

            qDebug() << "Register to SIP server failure.";

            //            m_LogList.ResetContent();

            return;
        }

        //        SetTimer(TIMER_EVENT_AUDIO_LEVEL, 100, NULL);

        //        m_LogList.InsertString(m_LogList.GetCount(), "Registering....");
    }
}

void loadDevices()
{
    int nums = PortSIP_getNumOfPlayoutDevices(m_SIPLib);

    char deviceName[1024] = { 0 };

    for (int i=0; i<nums; ++i)
    {
        PortSIP_getPlayoutDeviceName(m_SIPLib, i, deviceName, 1024);
    }

    nums = PortSIP_getNumOfRecordingDevices(m_SIPLib);
    for (int i=0; i<nums; ++i)
    {
        PortSIP_getRecordingDeviceName(m_SIPLib, i, deviceName, 1024);
    }

    char uniqueIdUTF8[1024] = { 0 };
    nums = PortSIP_getNumOfVideoCaptureDevices(m_SIPLib);

    for (int i=0; i<nums; ++i)
    {
        PortSIP_getVideoCaptureDeviceName(m_SIPLib, i,uniqueIdUTF8,1024, deviceName, 1024);
    }

    m_PCMA = TRUE;
    m_PCMU = TRUE;
    m_G729 = TRUE;

    m_H264 = TRUE;

    m_AEC = TRUE;
    m_VAD = TRUE;
    m_AGC = TRUE;
    m_CNG = TRUE;
    m_ANS = TRUE;
}

void setSRTPType()
{
    if (sipInitialized == false)
    {
        return;
    }

    SRTP_POLICY srtpPolicy = SRTP_POLICY_NONE;

    //	switch (m_cmbSRTPMode.GetCurSel())
    //	{
    //	case 0:
    //		srtpPolicy = SRTP_POLICY_NONE;
    //		break;
    //	case 1:
    //		srtpPolicy = SRTP_POLICY_PREFER;
    //		break;
    //	case 2:
    //		srtpPolicy = SRTP_POLICY_FORCE;
    //		break;
    //	}

    PortSIP_setSrtpPolicy(m_SIPLib, srtpPolicy);
}

void updateAudioCodecs()
{
    if (sipInitialized == false)
    {
        return;
    }

    PortSIP_clearAudioCodec(m_SIPLib);



    if (m_PCMU)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_PCMU);
    }

    if (m_PCMA)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_PCMA);
    }
    if (m_G729)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_G729);
    }
    if (m_ILBC)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_ILBC);
    }
    if (m_GSM)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_GSM);
    }

    if (m_G722)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_G722);
    }
    if (m_SPEEX)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_SPEEX);
    }

    if (m_SPEEX_WB)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_SPEEXWB);
    }

    if (m_AMR)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_AMR);
    }

    if (m_AMRWB)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_AMRWB);
    }
    if (m_G7221)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_G7221);
    }

    if (m_Opus)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_OPUS);
    }


    PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_DTMF);
}

void updateVideoCodecs()
{
    if (sipInitialized == false)
    {
        return;
    }

    PortSIP_clearVideoCodec(m_SIPLib);


    //UpdateData(TRUE);

    if (m_H263)
    {
        PortSIP_addVideoCodec(m_SIPLib, VIDEO_CODEC_H263);
    }

    if (m_H2631998)
    {
        PortSIP_addVideoCodec(m_SIPLib, VIDEO_CODEC_H263_1998);
    }

    if (m_H264)
    {
        PortSIP_addVideoCodec(m_SIPLib, VIDEO_CODEC_H264);
    }

    if (m_VP8)
    {
        PortSIP_addVideoCodec(m_SIPLib, VIDEO_CODEC_VP8);
    }
}

void initSettings()
{
    if (sipInitialized == false)
    {
        return;
    }

    //UpdateData(TRUE);

    PortSIP_enableAEC(m_SIPLib, m_AEC==TRUE);
    PortSIP_enableCNG(m_SIPLib, m_CNG==TRUE);
    PortSIP_enableAGC(m_SIPLib, m_AGC==TRUE);
    PortSIP_enableANS(m_SIPLib, m_ANS==TRUE);
    PortSIP_enableVAD(m_SIPLib, m_VAD==TRUE);

    PortSIP_setDoNotDisturb(m_SIPLib, m_DND==TRUE);
}

void setVideoResolution()
{
    if (sipInitialized == false)
    {
        return;
    }

    VIDEO_RESOLUTION videoResolution = VIDEO_CIF;
    /*
    switch (m_cmbVideoResolution.GetCurSel())
    {
    case 0:
        videoResolution = VIDEO_QCIF;
        break;
    case 1:
        videoResolution = VIDEO_CIF;
        break;
    case 2:
        videoResolution = VIDEO_VGA;
        break;
    case 3:
        videoResolution = VIDEO_SVGA;
        break;
    case 4:
        videoResolution = VIDEO_XVGA;
        break;
    case 5:
        videoResolution = VIDEO_720P;
        break;
    case 6:
        videoResolution = VIDEO_QVGA;
        break;
    }
    */

    PortSIP_setVideoResolution(m_SIPLib,videoResolution);
}

void setVideoBitrate()
{
    if (sipInitialized == false)
    {
        return;
    }

    if(sipInitialized)
    {
        //PortSIP_setVideoBitrate(m_SIPLib,m_sliderVideoBitrate.GetPos());
    }
    //m_strBitrate.Format("%dKbps",m_sliderVideoBitrate.GetPos());
    //UpdateData(FALSE);
}

void button1Click()
{
//    updateAudioCodecs();
//    updateVideoCodecs();

//    updatePrackSetting();

//    if (PortSIP_isAudioCodecEmpty(m_SIPLib) == true)
//    {
//        initDefaultAudioCodecs();
//    }

//    stringstream to;
//    to << (LPTSTR)(LPCTSTR)m_PhoneNumber;



//    bool hasSDP = true;  // Usually to make the 3PCC, you need to make an invite without SDP
//    if (m_CallSDP)
//    {
//        hasSDP = false;
 //   }


    PortSIP_setAudioDeviceId(m_SIPLib, 0, 0);


    // The callee MUST likes sip:number@sip.portsip.com
    int errorCode = 0;
//    bool makeVideoCall = false;
//    if (m_MakeVideoCall)
//    {
//        makeVideoCall = true;
//    }

    long sessionId = PortSIP_call(m_SIPLib, "sip:1003@172.16.1.152", false, false);
    if (sessionId <= 0)
    {
        if(errorCode != 0)
        {
            //showErrorMessage(errorCode);
        }
        qDebug() << "PortSIP_call failure.";
        return;
    }

//    PortSIP_setRemoteVideoWindow(m_SIPLib, sessionId, m_RemoteVideo.m_hWnd);

//    m_SessionArray[m_ActiveLine].setSessionId(sessionId);
//    m_SessionArray[m_ActiveLine].setSessionState(true);


//    stringstream text;
//    text << "Calling on line " << m_ActiveLine << "";

//    m_LogList.InsertString(m_LogList.GetCount(), text.str().c_str());
}

void onMessage(void *parameters)
{
    if (parameters == NULL)
    {
        qDebug() << "NULL";
        return;
    }

    ICallbackParameters* parameter = reinterpret_cast<ICallbackParameters *>(parameters);

//    int eventType = parameter->getEventType();

    char* c = (char*)parameters;

    int eventType = ((int*)(&c[24]))[0];

    int* in = (int*)parameters;



    switch(eventType)
    {
    case SIP_UNKNOWN:
        break;

    case SIP_REGISTER_SUCCESS:
        qDebug() << "SIP_REGISTER_SUCCESS";
        break;

    case SIP_REGISTER_FAILURE:
        qDebug() << "SIP_REGISTER_FAILURE";
        break;

    case SIP_INVITE_INCOMING:
    {
        qDebug() << "SIP_INVITE_INCOMING";

        for (int i=0; i<1024*4; i++)
        {
            //if (c[i] !=0)
            printf("%d ", c[i]);
        }
        puts("\n---");
    //    printf("%d\n", eventType);
        fflush(stdout);

        int rt = PortSIP_answerCall(Widget::m_SIPLib, 1, false);


     }
        break;

    case SIP_INVITE_TRYING:
        qDebug() << "SIP_INVITE_TRYING";
        break;

    case SIP_INVITE_SESSION_PROGRESS:
        qDebug() << "SIP_INVITE_SESSION_PROGRESS";
        break;

    case SIP_INVITE_RINGING:
        qDebug() << "SIP_INVITE_RINGING";
        break;

    case SIP_INVITE_ANSWERED:
        break;

    case SIP_INVITE_FAILURE:
        break;

    case SIP_INVITE_UPDATED:
        break;

    case SIP_INVITE_CONNECTED:
        break;

    case SIP_INVITE_BEGINING_FORWARD:
        break;

    case SIP_INVITE_CLOSED:
        break;

    case SIP_REMOTE_HOLD:
        break;

    case SIP_REMOTE_UNHOLD:
        break;

    case SIP_RECEIVED_REFER:
        break;

    case SIP_REFER_ACCEPTED:
        break;

    case SIP_REFER_REJECTED:
        break;

    case SIP_TRANSFER_TRYING:
        break;

    case SIP_TRANSFER_RINGING:
        break;

    case SIP_ACTV_TRANSFER_SUCCESS:
        break;

    case SIP_ACTV_TRANSFER_FAILURE:
        break;

    case SIP_RECEIVED_SIGNALING:
        break;

    case SIP_SENDING_SIGNALING:
        break;

    case SIP_WAITING_VOICEMESSAGE:
        break;

    case SIP_WAITING_FAXMESSAGE:
        break;

    case SIP_RECV_DTMFTONE:
        break;

    case SIP_PRESENCE_RECV_SUBSCRIBE:
        break;

    case SIP_PRESENCE_ONLINE:
        break;

    case SIP_PRESENCE_OFFLINE:
        break;

    case SIP_RECV_OPTIONS:
        break;

    case SIP_RECV_INFO:
        break;

    case SIP_RECV_MESSAGE:
        break;

    case SIP_RECV_OUTOFDIALOG_MESSAGE:
        break;

    case SIP_SEND_MESSAGE_SUCCESS:
        break;

    case SIP_SEND_MESSAGE_FAILURE:
        break;

    case SIP_SEND_OUTOFDIALOG_MESSAGE_SUCCESS:
        break;

    case SIP_SEND_OUTOFDIALOG_MESSAGE_FAILURE:
        break;

    case SIP_PLAY_AUDIO_FILE_FINISHED:
        break;

    case SIP_PLAY_VIDEO_FILE_FINISHED:
        break;
    }
}
